using System;
using System.Collections.Generic;
using System.Text;
using Musicman.Entities.BusinessEntities;
using Musicman.Common;
using System.Threading;

namespace Musicman.Utilities
{
    public class UpdateManager
    {
        # region singleton definition
        static readonly UpdateManager instance = new UpdateManager();
        
        public static UpdateManager Instance
        {
            get
            {
                return instance;
            }
        }
        static UpdateManager()
        {
            instance.Initialize();
        }

        # endregion


        private FileFinder fileFinder = null;
        SearchJobsConfigurationSection myJobs = null;
        CronConfigurationSection cronSection = null;
        private DateTime nextDate = DateTime.Today;
        private SearchLoactionConfigurationElementCollection locations; // = new SearchLoactionConfigurationElementCollection();
        private bool searchRunning = false;
        private int jobCount = 0;
        private Thread _cronThread;
        private int _loopTime = 60000;  // check each minute
        private bool _run = true;

        private void Initialize()
        {
            locations = new SearchLoactionConfigurationElementCollection();
            myJobs = (SearchJobsConfigurationSection)AppSettingsHelper.GetWebConfigSection("MyJobs");
            cronSection = (CronConfigurationSection)AppSettingsHelper.GetWebConfigSection("CronConfig");
            nextDate = instance.cronSection.Settings.StartDate;
            _loopTime = instance.cronSection.Settings.LoopMinutes * 60000; // miliseconds
            FindNextDate();
            _cronThread = new Thread(new ThreadStart(createMonitoringThread));
        }

        private FileFinder getFileFinder()
        {
            if (this.fileFinder == null)
            {
                this.fileFinder = new FileFinder();
                fileFinder.FileFindCompleted += new FileFindCompletedEventHandler(instance.ff_FileFindCompleted);
            }
            return this.fileFinder;
        }


        private void createMonitoringThread()
        {
            while (_run)
            {
                try
                {
                    Thread.Sleep(_loopTime);
                    if (DateTime.Now > this.nextDate)
                    {
                        FindNextDate();
                        RunSearchJob();
                    }
                }
                catch (Exception e)
                {
                    LogManager.LogException("Error in cron job", e);
                }
            }
        }

        void ff_FileFindCompleted(object sender, FileFindCompletedEventArgs e)
        {
            LogManager.LogInfo(String.Format("Total time: {0} \r\nTotal files found: {1} \r\nTotal size: {2} \r\nTotal files added: {3} \r\nTotal files deleted: {4} \r\nTotal files modified: {5}\r\n",
                e.TotalTime, e.TotalFiles, e.TotalFileSize, e.TotalAdded, e.TotalDeleted, e.TotalModified));
            if (this.jobCount != myJobs.Jobs.Count)
            {
                SearchJobConfigurationElement job = new SearchJobConfigurationElement();
                job.AllCriteria = myJobs.Jobs[jobCount].AllCriteria;
                job.Name = myJobs.Jobs[jobCount].Name;
                job.Stype = myJobs.Jobs[jobCount].Stype;
                job.Minsize = myJobs.Jobs[jobCount].Minsize;
                job.Maxsize = myJobs.Jobs[jobCount].Maxsize;
                jobCount++;
                getFileFinder().SearchFilesAsync(job, this.locations);
            }
            else
            {
                searchRunning = false;
                LogManager.LogInfo(String.Format("Next run at -- {0}", nextDate));
                this.jobCount = 0;
                this.fileFinder = null;
                GC.Collect();
                GC.WaitForPendingFinalizers();
            }
        }

        public void RunSearchJob()
        {
            if (this.jobCount != myJobs.Jobs.Count && !searchRunning)
            {
                this.locations = myJobs.Locations;
                searchRunning = true;
                SearchJobConfigurationElement job = new SearchJobConfigurationElement();
                job.AllCriteria = myJobs.Jobs[jobCount].AllCriteria;
                job.Name = myJobs.Jobs[jobCount].Name;
                job.Stype = myJobs.Jobs[jobCount].Stype;
                job.Minsize = myJobs.Jobs[jobCount].Minsize;
                job.Maxsize = myJobs.Jobs[jobCount].Maxsize;
                jobCount++;
                getFileFinder().SearchFilesAsync(job, this.locations);
            }
            else
            {
                if (searchRunning)
                {
                    LogManager.LogInfo("Search job not started, another one already running");
                }
                else
                {
                    LogManager.LogInfo("Search job not started, no jobs defined for search");
                }
            }
        }

        public void StartCron()
        {
            LogManager.LogInfo("Starting Indexing Service");
            LogManager.LogInfo(myJobs.ToString());
            LogManager.LogInfo(String.Format("Next run at -- {0}", nextDate));
            _cronThread.Start();
        }

        public void StopCron()
        {
            LogManager.LogInfo("Stopping Indexing Service"); 
            // _cronThread.Abort();
            this._run = false;
        }

        public void FindNextDate()
        {
            if (this.cronSection.Settings.Days == 0)
            {
                this.nextDate = DateTime.Today;
            }
            while (this.nextDate < DateTime.Now)
            {
                this.nextDate = this.nextDate.AddDays(this.cronSection.Settings.Days);
                this.nextDate = this.nextDate.AddHours(this.cronSection.Settings.Hours);
                this.nextDate = this.nextDate.AddMinutes(this.cronSection.Settings.Minutes);
            }
        }
    }
}
